use proc_macro::{TokenStream};
use quote::quote;
use syn::{parse_macro_input, ItemFn, ReturnType, Type};
use crate::parse::parse_param;
use crate::util::to_upper_name;

pub fn do_receive_router(_attr: TokenStream, item: TokenStream) -> TokenStream {
    let input_fn = parse_macro_input!(item as ItemFn);
    let sig = &input_fn.sig;
    let fn_name = &sig.ident;

    let method_upper_name = to_upper_name(&fn_name.clone().to_string());
    let router_factory = syn::Ident::new(&format!("{}RouterFactory", method_upper_name), fn_name.span());
    let router = syn::Ident::new(&format!("{}Router", method_upper_name), fn_name.span());

    let is_result = return_type_is_result(&sig.output);

    let param = parse_param(&sig);
    let params = param.params;
    let fields = param.fields;
    let mut_params = param.mut_params;
    let param_types = param.param_types;
    let has_context = param.has_context;

    let parse_code = if params.len() > 1 {
        quote! {
            let (#(#params),*) = rpc::decode::<(#(#param_types),*)>(rpc_context, byte_muts.freeze().to_vec())?;
            Ok(Box::new(#router {
               #(#params),*
            }))
        }
    } else {
        quote! {
            Ok(Box::new(#router {
               #(#params: rpc::decode::<#param_types>(rpc_context, byte_muts.freeze().to_vec())?,)*
            }))
        }
    };

    let executor = if has_context {
        if is_result {
            quote! {
                let result = #fn_name(rpc_context, #(#mut_params),*);
                match result {
                    Ok(result) => Ok(Box::new(result)),
                    Err(error) => Err(error.into()),
                }
            }
        } else {
            quote! {
                let result = #fn_name(rpc_context, #(#mut_params),*);
                Ok(Box::new(result))
            }
        }
    } else {
        if is_result {
            quote! {
                let result = #fn_name(#(#mut_params),*);
                match result {
                    Ok(result) => Ok(Box::new(result)),
                    Err(error) => Err(error.into()),
                }
            }
        } else {
            quote! {
                let result = #fn_name(#(#mut_params),*);
                Ok(Box::new(result))
            }
        }
    };

    // 生成代码
    let expanded = quote! {
        #input_fn

        pub struct #router_factory;

        #[derive(Debug)]
        pub struct #router {
            #(#fields),*
        }

        impl rpc::router::RouterFactory for #router_factory {
            fn parse(&self, rpc_context: &rpc::RpcContext, byte_muts:bytes::BytesMut)->rpc::RpcResult<Box<dyn rpc::router::DoRouter>>{
                #parse_code
            }
        }

        impl rpc::router::DoRouter for #router {
            fn execute(&mut self, mut rpc_context: &mut rpc::RpcContext) -> rpc::RpcResult<Box<dyn rpc::codec::RpcEncode>> {
                #executor
            }
        }
    };

    TokenStream::from(expanded)
}

fn return_type_is_result(return_type: &ReturnType)-> bool {
    if let ReturnType::Type(_, return_type_box) = return_type {
        if let Type::Path(type_path) = return_type_box.as_ref() {
            // 获取路径的最后一段，对于 `Result<String, ...>` 就是 `Result`
            let last_segment = type_path.path.segments.last().unwrap();
            if last_segment.ident == "Result" || last_segment.ident == "RpcResult"{
                return true;
            }
        }
    }
    false
}

